package BandB.Tool.GPhoneManager.TaskManager.Util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import BandB.Tool.GPhoneManager.TaskManager.ProcessList;
import BandB.Tool.GPhoneManager.TaskManager.ApplicationInfo;
import BandB.Tool.GPhoneManager.TaskManager.RuntimeInfo;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
import android.net.Uri;
import android.os.IBinder;
import android.util.Log;
import android.webkit.MimeTypeMap;

/**
 * Various utilities shared amongst the Launcher's classes.
 */
public final class Utilities {
	private static int sIconWidth = -1;
	private static int sIconHeight = -1;

	private static final Paint sPaint = new Paint();
	private static final Rect sBounds = new Rect();
	private static final Rect sOldBounds = new Rect();
	private static final String TAG = "TaskManager Utilites";
	private static Canvas sCanvas = new Canvas();
	static final int KILL_PIDS_FOR_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 79;
	static {
		sCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
				Paint.FILTER_BITMAP_FLAG));
	}

	/**
	 * Returns a Drawable representing the thumbnail of the specified Drawable.
	 * The size of the thumbnail is defined by the dimension
	 * android.R.dimen.launcher_application_icon_size.
	 * 
	 * This method is not thread-safe and should be invoked on the UI thread
	 * only.
	 * 
	 * @param icon
	 *            The icon to get a thumbnail of.
	 * @param context
	 *            The application's context.
	 * 
	 * @return A thumbnail for the specified icon or the icon itself if the
	 *         thumbnail could not be created.
	 */
	public static Drawable createIconThumbnail(Drawable icon, Context context) {
		if (sIconWidth == -1) {
			final Resources resources = context.getResources();
			sIconWidth = sIconHeight = (int) resources
					.getDimension(android.R.dimen.app_icon_size);
		}

		int width = sIconWidth;
		int height = sIconHeight;

		final int iconWidth = icon.getIntrinsicWidth();
		final int iconHeight = icon.getIntrinsicHeight();

		if (icon instanceof PaintDrawable) {
			PaintDrawable painter = (PaintDrawable) icon;
			painter.setIntrinsicWidth(width);
			painter.setIntrinsicHeight(height);
		}

		if (width > 0 && height > 0) {
			if (width < iconWidth || height < iconHeight) {
				final float ratio = (float) iconWidth / iconHeight;

				if (iconWidth > iconHeight) {
					height = (int) (width / ratio);
				} else if (iconHeight > iconWidth) {
					width = (int) (height * ratio);
				}

				final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
						: Bitmap.Config.RGB_565;
				final Bitmap thumb = Bitmap.createBitmap(sIconWidth,
						sIconHeight, c);
				final Canvas canvas = sCanvas;
				canvas.setBitmap(thumb);
				// Copy the old bounds to restore them later
				// If we were to do oldBounds = icon.getBounds(),
				// the call to setBounds() that follows would
				// change the same instance and we would lose the
				// old bounds
				sOldBounds.set(icon.getBounds());
				final int x = (sIconWidth - width) / 2;
				final int y = (sIconHeight - height) / 2;
				icon.setBounds(x, y, x + width, y + height);
				icon.draw(canvas);
				icon.setBounds(sOldBounds);
				icon = new FastBitmapDrawable(thumb);
			} else if (iconWidth < width && iconHeight < height) {
				final Bitmap.Config c = Bitmap.Config.ARGB_8888;
				final Bitmap thumb = Bitmap.createBitmap(sIconWidth,
						sIconHeight, c);
				final Canvas canvas = sCanvas;
				canvas.setBitmap(thumb);
				sOldBounds.set(icon.getBounds());
				final int x = (width - iconWidth) / 2;
				final int y = (height - iconHeight) / 2;
				icon.setBounds(x, y, x + iconWidth, y + iconHeight);
				icon.draw(canvas);
				icon.setBounds(sOldBounds);
				icon = new FastBitmapDrawable(thumb);
			}
		}

		return icon;
	}

	/**
	 * Returns a Bitmap representing the thumbnail of the specified Bitmap. The
	 * size of the thumbnail is defined by the dimension
	 * android.R.dimen.launcher_application_icon_size.
	 * 
	 * This method is not thread-safe and should be invoked on the UI thread
	 * only.
	 * 
	 * @param bitmap
	 *            The bitmap to get a thumbnail of.
	 * @param context
	 *            The application's context.
	 * 
	 * @return A thumbnail for the specified bitmap or the bitmap itself if the
	 *         thumbnail could not be created.
	 */
	static Bitmap createBitmapThumbnail(Bitmap bitmap, Context context) {
		if (sIconWidth == -1) {
			final Resources resources = context.getResources();
			sIconWidth = sIconHeight = (int) resources
					.getDimension(android.R.dimen.app_icon_size);
		}

		int width = sIconWidth;
		int height = sIconHeight;

		final int bitmapWidth = bitmap.getWidth();
		final int bitmapHeight = bitmap.getHeight();

		if (width > 0 && height > 0
				&& (width < bitmapWidth || height < bitmapHeight)) {
			final float ratio = (float) bitmapWidth / bitmapHeight;

			if (bitmapWidth > bitmapHeight) {
				height = (int) (width / ratio);
			} else if (bitmapHeight > bitmapWidth) {
				width = (int) (height * ratio);
			}

			final Bitmap.Config c = (width == sIconWidth && height == sIconHeight) ? bitmap
					.getConfig()
					: Bitmap.Config.ARGB_8888;
			final Bitmap thumb = Bitmap
					.createBitmap(sIconWidth, sIconHeight, c);
			final Canvas canvas = sCanvas;
			final Paint paint = sPaint;
			canvas.setBitmap(thumb);
			paint.setDither(false);
			paint.setFilterBitmap(true);
			sBounds.set((sIconWidth - width) / 2, (sIconHeight - height) / 2,
					width, height);
			sOldBounds.set(0, 0, bitmapWidth, bitmapHeight);
			canvas.drawBitmap(bitmap, sOldBounds, sBounds, paint);
			return thumb;
		}

		return bitmap;
	}

	public static ArrayList<ApplicationInfo> getRunningAppList(Context context) {
		Map<String, ApplicationInfo> map = new HashMap<String, ApplicationInfo>();
		ArrayList<ApplicationInfo> appList = new ArrayList<ApplicationInfo>();
		PackageManager pm = context.getPackageManager();
		ActivityManager am = (ActivityManager) context
				.getSystemService(Activity.ACTIVITY_SERVICE);
		List<RunningAppProcessInfo> apps = am.getRunningAppProcesses();
		// ArrayList<String> packageNames = new ArrayList<String>();
		for (RunningAppProcessInfo runningAppProcessInfo : apps) {
			for (String pkg : runningAppProcessInfo.pkgList) {
				if (!map.containsKey(pkg)
						&& !pkg.startsWith("com.android.providers")) {
					ApplicationInfo info = new ApplicationInfo();
					try {
						android.content.pm.ApplicationInfo appInfo = pm
								.getApplicationInfo(pkg, 0);
						if (appInfo.packageName
								.equalsIgnoreCase(ProcessList.ANDROID_SYSTEM)) {
							continue;
						}
						info.setTitle(appInfo.loadLabel(pm).toString());
						info.setIcon(appInfo.loadIcon(pm));
						info.setAppInfo(appInfo);
						info.setPid(runningAppProcessInfo.pid);
						appList.add(info);
						// packageNames.add(pkg);
						map.put(pkg, info);
					} catch (NameNotFoundException e) {
						// TODO Auto-generated catch block
						Log.e(TAG, e.toString());
					}
				}
			}
		}

		List<RunningServiceInfo> services = am.getRunningServices(100);
		for (RunningServiceInfo service : services) {
			String pkg = service.service.getPackageName();
			if (!map.containsKey(pkg)
					&& !pkg.startsWith("com.android.providers")) {
				ApplicationInfo info = new ApplicationInfo();
				try {
					android.content.pm.ApplicationInfo appInfo = pm
							.getApplicationInfo(service.service
									.getPackageName(), 0);
					info.setTitle(appInfo.loadLabel(pm).toString());
					info.setIcon(appInfo.loadIcon(pm));
					info.setAppInfo(appInfo);
					info.setPid(service.pid);
					appList.add(info);
					// packageNames.add(info.getAppInfo().packageName);
					map.put(pkg, info);
				} catch (NameNotFoundException e) {
					// TODO Auto-generated catch block
					Log.e(TAG, e.toString());
				}
			}
		}

		List<RunningTaskInfo> tasks = am.getRunningTasks(100);
		for (RunningTaskInfo runningTaskInfo : tasks) {
			try {
				ComponentName topActivity = runningTaskInfo.topActivity;
				String pkg = topActivity.getPackageName();
				if (map.containsKey(pkg)) {
					ApplicationInfo info = map.get(pkg);
					info.setTopActivity(topActivity);
					map.put(pkg, info);
				} else {
					ApplicationInfo info = new ApplicationInfo();
					android.content.pm.ApplicationInfo appInfo = pm
							.getApplicationInfo(runningTaskInfo.topActivity
									.getPackageName(), 0);
					info.setTitle(appInfo.loadLabel(pm).toString());
					info.setIcon(appInfo.loadIcon(pm));
					info.setAppInfo(appInfo);
					info.setTopActivity(runningTaskInfo.topActivity);
					appList.add(info);
					map.put(pkg, info);
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				Log.e(TAG, e.toString());
			}
		}
		return appList;
	}

	public static String formateSize(long size) {
		if (size < (1 << 10)) {
			return size + "B";
		} else if (size < (1 << 20)) {
			return (size >> 10) + "KB";
		} else if (size < (1 << 30)) {
			return (size >> 20) + "MB";
		} else if (size < (1 << 40)) {
			return (size >> 30) + "GB";
		} else {
			return (size >> 40) + "TB";
		}
	}

	public static RuntimeInfo getCpuUsageByPid(int pid, String cache) {
		RuntimeInfo info = new RuntimeInfo();
		try {
			BufferedReader br = null;
			if (cache == null) {
				String cmd = "top -n 1";
				Process process;
				Runtime runtime = Runtime.getRuntime();
				process = runtime.exec(cmd);
				InputStream is = process.getInputStream();
				InputStreamReader isr = new InputStreamReader(is);
				br = new BufferedReader(isr);
			} else {
				StringReader sr = new StringReader(cache);
				br = new BufferedReader(sr);
			}

			String line;
			while ((line = br.readLine()) != null) {
				String segs[] = line.trim().split("[ ]+");
				if (segs[0].equalsIgnoreCase(String.valueOf(pid))) {
					info.setPid(pid);
					info
							.setCpuUsage(Integer.parseInt(segs[1].replace("%",
									"")));
					info.setThreadCount(Integer.parseInt(segs[3]));
					info.setMemoryUsage(Long
							.parseLong(segs[5].replace("K", "")) << 10);
					break;
				}
			}
		} catch (Exception e) {
			e.fillInStackTrace();
			Log.e("Process Manager", "Unable to execute top command");
		}
		return info;
	}

	public static String getAllCpuUsage(String cache) {
		try {
			BufferedReader br = null;
			if (cache == null) {
				String cmd = "top -n 1";
				Process process;
				Runtime runtime = Runtime.getRuntime();
				process = runtime.exec(cmd);
				InputStream is = process.getInputStream();
				InputStreamReader isr = new InputStreamReader(is);
				br = new BufferedReader(isr);
			} else {
				StringReader sr = new StringReader(cache);
				br = new BufferedReader(sr);
			}

			String line;
			while ((line = br.readLine()) != null) {
				if (line.length() > 0) {
					return line;
				}
			}
		} catch (Exception e) {
			e.fillInStackTrace();
			Log.e("Process Manager", "Unable to execute top command");
		}
		return "";
	}

	public static String getFileExtension(File file) {
		if (file == null || file.isDirectory()) {
			return "";
		} else {
			int index = file.getName().lastIndexOf(".");
			String ext = "";
			if (index != -1) {
				ext = file.getName().substring(index);
			}
			return ext;
		}
	}

	public static void tryOpenFile(Context context, File file) {
		String type = getMimeType(file);
		if (type != null) {
			Uri uri = Uri.parse("file://" + file.getPath());
			Intent intent = new Intent(Intent.ACTION_VIEW);
			intent.setDataAndType(uri, type);
			intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
			context.startActivity(intent);
		}
	}

	public static String getMimeType(File file) {
		String ext = getFileExtension(file);

		String type = null;
		// if(ext.equalsIgnoreCase(".apk")){
		// type = "application/vnd.android.package-archive";
		// }
		// else if (ext.equalsIgnoreCase(".jpg")||
		// ext.equalsIgnoreCase(".gif") ||
		// ext.equalsIgnoreCase(".png") ||
		// ext.equalsIgnoreCase(".bmp")) {
		// type = "vnd.android.cursor.dir/image";
		// }
		// else if (ext.equalsIgnoreCase(".mp3")||
		// ext.equalsIgnoreCase(".ogg") ||
		// ext.equalsIgnoreCase(".wav") ||
		// ext.equalsIgnoreCase(".3gp") ||
		// ext.equalsIgnoreCase(".mp4")) {
		// type = "vnd.android.cursor.dir/video";
		// }
		if (ext.equalsIgnoreCase(".txt") || ext.equalsIgnoreCase(".htm")
				|| ext.equalsIgnoreCase(".html")) {
			type = "text/plain";
		} else {
			type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
					ext.replace(".", ""));
		}
		return type;
	}

	// 拷贝文件
	private static void copyFile(File source, File dest) throws Exception {
		File in = source;
		File out = dest;
		FileInputStream inFile = new FileInputStream(in);
		FileOutputStream outFile = new FileOutputStream(out);
		byte[] buffer = new byte[1024];
		int i = 0;
		while ((i = inFile.read(buffer)) != -1) {
			outFile.write(buffer, 0, i);
		}// end while
		inFile.close();
		outFile.close();
	}// end copyFile

	// 处理目录
	private static void copyDir(final File source, final File dest)
			throws Exception {
		File source1;
		File dest1;

		final File[] file = source.listFiles();
		final int length = file.length;
		for (int i = 0; i < length; i = i + 1) {
			if (file[i].isFile()) {
				source1 = file[i];
				dest1 = new File(dest, file[i].getName());
				copyFile(source1, dest1);
			}// end if
		}
		for (int i = 0; i < length; i = i + 1) {
			if (file[i].isDirectory()) {
				source1 = file[i];
				dest1 = new File(dest, file[i].getName());
				dest1.mkdir();
				copyDir(source1, dest1);
			}// end if
		}
	}// end copyDict

	private static void deleteDir(final File file) throws Exception {
		final File[] files = file.listFiles();
		final int length = files.length;
		for (int i = 0; i < length; i = i + 1) {
			if (files[i].isFile()) {
				deleteFile(files[i]);
			}// end if
		}
		for (int i = 0; i < files.length; i = i + 1) {
			if (files[i].isDirectory()) {
				deleteDir(files[i]);
			}// end if
		}
		final boolean deleteSuccess = file.delete();
		if (deleteSuccess) {
			Log.i(TAG, "succeed to delete file");
		} else {
			Log.i(TAG, "fail  to delete file");
		}
	}

	private static void deleteFile(final File file) throws Exception {
		if (!file.delete()) {
			throw new Exception();
		}
	}

	// 拷贝文件
	private static void cutFile(final File source, File dest) throws Exception {
		copyFile(source, dest);
		deleteFile(source);
	}// end copyFile

	// 处理目录
	private static void cutDir(File source, File dest) throws Exception {
		copyDir(source, dest);
		deleteDir(source);
	}// end copyDict

	public static void fileCut(File source, File dest) throws Exception {
		if (source.equals(dest)) {
			return;
		}
		if (source.isDirectory() && dest.isDirectory()) {
			cutDir(source, dest);
		} else if (!source.isDirectory() && !dest.isDirectory()) {
			cutFile(source, dest);
		}
	}

	public static void fileCopy(File source, File dest) throws Exception {
		if (source.equals(dest)) {
			dest = new File(dest.getPath(), "Copy of " + dest.getName());
		}
		if (source.isDirectory() && dest.isDirectory()) {
			copyDir(source, dest);
		} else if (!source.isDirectory() && !dest.isDirectory()) {
			copyFile(source, dest);
		}
	}

	public static void fileDelete(File source) throws Exception {
		if (source.isDirectory()) {
			deleteDir(source);
		} else {
			deleteFile(source);
		}
	}

	public static void fileRename(File source, File newName) throws Exception {
		if (!source.renameTo(newName)) {
			throw new Exception();
		}
	}

	public static void newFolder(File folder) throws Exception {
		if (!folder.mkdir()) {
			throw new Exception();
		}
	}

}
